package com.kehutong.charge.service.impl;

import com.kehutong.charge.dao.ChargeMeterDao;
import com.kehutong.charge.dto.MeterReadStatistDTO;
import com.kehutong.charge.dto.MeterReadingImportDTO;
import com.kehutong.charge.entity.*;
import com.kehutong.charge.service.*;
import com.kehutong.charge.util.CommonClient;
import com.kehutong.charge.util.CommonUtil;
import com.kehutong.charge.util.ConvertUtil;
import com.kehutong.charge.util.JDBCUtil;
import com.kehutong.charge.util.enums.ChargeLogEnum;
import com.kehutong.charge.util.enums.ChargeStatusEnum;
import com.kehutong.charge.util.enums.MeterTypeEnum;
import com.kehutong.charge.vo.*;
import com.kehutong.common.DailyUtil;
import com.kehutong.common.DeptService;
import com.kehutong.common.Java8TimeUtils;
import com.kehutong.common.constant.RegexConstant;
import com.kehutong.common.dto.DeptDTO;
import com.kehutong.common.errcode.Assert;
import com.kehutong.common.errcode.Result;
import com.kehutong.common.excel.entity.ImportResult;
import com.kehutong.common.excel.tool.ExcelTool;
import com.kehutong.common.util.*;
import org.coraframework.bean.Beans;
import org.coraframework.converter.util.StringUtil;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.Condition;
import org.coraframework.orm.jdbc.execute.PageCondition;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @program: kht
 * @description: ChargeFeeServiceImpl
 * @author: joneron
 * @create: 2021/6/29
 **/
public class MeterReadServiceImpl implements MeterReadService {

    private static final Logger logger = LoggerFactory.getLogger(MeterReadServiceImpl.class);



    @Inject
    DeptService deptService;
    @Inject
    private JdbcSession jdbcSession;
    @Inject
    ChargeMeterDao chargeMeterDao;
    @Inject
    CommonClient commonClient;

    @Inject
    ExcelTool excelTool;
    @Inject
    MeterClassifyService meterClassifyService;
    @Inject
    ChargeHouseService houseService;
    @Inject
    ChargeProjectService chargeProjectService;

    @Inject
    CommonService commonService;


    @Override
    public Page<MeterReading> findPage(JSONObject jsonObject) {
        FindPage<MeterReading> find = jdbcSession.findPage(MeterReading.class)
                .eq("deleted", false)
                .eq(jsonObject, "meterType")
                .like(jsonObject, "meterNo")
                .eq(jsonObject, "meterClassifyNo")
                .eq(jsonObject, "meterTypeNo")
                .like(jsonObject, "meterNumber")
                .eq(jsonObject, "communityNo")
                .eq(jsonObject, "houseNo")
                .eq(jsonObject, "readYearMonth")
                .eq(jsonObject, "readStatus");

        // 处理时间
        JDBCUtil.between(jsonObject, find, "createTime");

        //添加选中导出条件
        JSONArray exportIdList = jsonObject.getJSONArray("exportIdList");
        if(!Objects.isEmpty(exportIdList)){
            find.in("id",exportIdList);
        }

        find.order("createTime", "desc").page(jsonObject);
        return find.exe();
    }


    @Override
    public void templateExport(HttpServletRequest req, HttpServletResponse resp,String meterTypeNo) {
        if(Objects.isBlank(meterTypeNo)){
            throw new RuntimeException("模板下载失败，请选择仪表类型.");
        }

        MeterTypeConfig typeConfig = jdbcSession.findOne(MeterTypeConfig.class)
                .eq("deleted", false)
                .eq("status", true)
                .eq("id", meterTypeNo)
                .exe();
        if(null == typeConfig || Objects.isBlank(typeConfig.getTypeName())){
            throw new RuntimeException("模板下载失败，传入的仪表类型不存在.");
        }
        String typeName = typeConfig.getTypeName();

        List<ReadingMeterTemplateExcelBaseVO> template = new ArrayList<>();

        ReadingMeterTemplateExcelBaseVO vo;
        if(MeterTypeEnum.METER_WATT.getDesc().equals(typeName)){
            vo = new ReadingAmmeterMeterTemplateExcelBaseVO();
        }else if(MeterTypeEnum.METER_WATER.getDesc().equals(typeName)){
            vo = new ReadingWaterMeterTemplateExcelBaseVO();
        }else{
            vo = new ReadingGasMeterTemplateExcelBaseVO();
        }

        vo.setMeterNo("DB20216010110（示例）");
        vo.setMeterTypeName(typeName);
        vo.setMeterClassifyName("业主仪表");
        vo.setCommunityName("七星小区");
        vo.setBuildName("1栋");
        vo.setUnitName("1单元");
        vo.setHouseNumber("1001");
        vo.setChargeName("张三");
        vo.setChargePhone("13243222222");
        vo.setTimeNumber("200");
        vo.setCreateTime("2021-06-01");
        vo.setCreateName("张三");
        vo.setStartTime("2021-05-01");
        vo.setEndTime("2021-05-31");
        template.add(vo);

        excelTool.excelDownload(req, resp, template, typeName+"抄表模板");
    }




    @Override
    public void pageExport(HttpServletRequest req, HttpServletResponse resp, JSONObject jsonObject) {
        jsonObject.put("pageNo", 1);
        jsonObject.put("pageSize", ExcelTool.MAX_ROWS);

        List<MeterReading> list = findPage(jsonObject).getList();
        Assert.notEmpty(list,"没有找到该小区的抄表数据");
        String meterTypeName = list.get(0).getMeterTypeName();
        Supplier vo;
        if(MeterTypeEnum.METER_WATT.getDesc().equals(meterTypeName)){
            vo = ReadingAmmeterMeterTemplateExcelBaseVO::new;
        }else if(MeterTypeEnum.METER_WATER.getDesc().equals(meterTypeName)){
            vo = ReadingWaterMeterTemplateExcelBaseVO::new;
        }else{
            vo = ReadingGasMeterTemplateExcelBaseVO::new;
        }
        List<ReadingMeterTemplateExcelBaseVO> readingList = ListUtils.copyList(list, vo);
        List<Map<String,Object>> houseList = null;
        try {
            Set<String> ids = readingList.stream().map(l -> l.getHouseNo()).collect(Collectors.toSet());
            JSONObject param = new JSONObject();
            param.put("ids",ids);
            houseList = commonClient.getHouseByIds(param);
        } catch (Exception e) {
            logger.error("抄表导出获取房屋信息错误",e);
            excelTool.excelDownload(req, resp, readingList, StringUtil.isEmpty(meterTypeName) ? "" : meterTypeName + "抄表统计导出");
        }
        List<Map<String, Object>> finalHouseList = houseList;
        readingList.stream().map(r-> finalHouseList.stream().filter(h->h.get("id").equals(r.getHouseNo())).findFirst().map(h->{
            r.setCommunityName(ConvertUtils.toNoNullString(h.get("communityName")));
            r.setBuildName(ConvertUtils.toNoNullString(h.get("buildName")));
            r.setUnitName(ConvertUtils.toNoNullString(h.get("unitName")));
            r.setHouseNumber(ConvertUtils.toNoNullString(h.get("mergeName")));
            return r;
        }).orElse(null)).filter(java.util.Objects::nonNull).collect(Collectors.toList());
        //修改抄表时间格式为yyyy-MM-dd
        readingList.forEach(r->r.setCreateTime(DateUtil.format(DateUtil.parse(r.getCreateTime(),
                DateUtil.YEAR_MONTH_DAY_HOUR_MINUTE_SECONDS_X),DateUtil.YEAR_MONTH_DAY)));
        excelTool.excelDownload(req, resp, readingList, StringUtil.isEmpty(meterTypeName) ? "" : meterTypeName + "抄表统计导出");
    }


    @Override
    public List<MeterReading> findList(JSONObject jsonObject) {
        return jdbcSession.findArray(MeterReading.class)
                .eq("deleted", false)
                .eq(jsonObject, "meterAddress")
                .eq(jsonObject, "houseNo")
                .eq(jsonObject, "readYearMonth")
                .eq(jsonObject, "meterTypeNo")
                .eq(jsonObject, "meterNo")
                .exe();
    }


    @Override
    public void importExcelCheck(JSONObject jsonObject) {
        excelTool.excelImport(jsonObject, MeterReadingImportDTO.class);
    }

    @Override
    public void feeSettleDetail(JSONObject jsonObject, Token token) {
        //获取房屋收费配置 todo 需要修改配置逻辑，待编码
        chargeProjectService.getConfig(jsonObject);



    }

    /**
     * @param jsonObject
     * @return
     * @Author jian Ye
     * 抄表Excel导入
     */
    @Override
    public Object listImport(JSONObject jsonObject, Token token) throws Exception {
        //初始化excel数据开始的行数，为每个数据添加下标
        Integer[] arr = {3};
        List<MeterReadingImportDTO> dtoList = excelTool.excelImport(jsonObject, MeterReadingImportDTO.class);
        dtoList = dtoList.stream().peek(d->d.setIndex(arr[0]++)).collect(Collectors.toList());

        int importTotal = dtoList.size();
        StringBuilder errorMsg = new StringBuilder();
        //抄表日期校验
        Set<String> importReadTimeSet = dtoList.stream().map(d -> d.getCreateTime()).collect(Collectors.toSet());
        Set<String> unRegexReadTimeSet = new HashSet<>(importReadTimeSet);
        unRegexReadTimeSet.removeIf(m-> RegexConstant.YEAR_MONTH_DAY_REGEX.matcher(m).find());
        if(!Objects.isEmpty(unRegexReadTimeSet)){
            List<Integer> errorIndex = dtoList.stream().filter(d -> unRegexReadTimeSet.contains(d.getCreateTime()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[抄表日期]格式错误.\n", errorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (isNull != null) {return isNull;}
        }

        //抄表时间范围校验
        Set<String> importStartTimeSet = dtoList.stream().map(d -> d.getStartTime().trim()).collect(Collectors.toSet());
        Set<String> unRegexStartTimeSet = new HashSet<>(importStartTimeSet);
        unRegexStartTimeSet.removeIf(m-> RegexConstant.YEAR_MONTH_DAY_REGEX.matcher(m).find());
        if(!Objects.isEmpty(unRegexStartTimeSet)){
            List<Integer> errorIndex = dtoList.stream().filter(d -> unRegexStartTimeSet.contains(d.getStartTime()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[抄表开始时间]格式错误.\n", errorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (isNull != null) {return isNull;}
        }
        Set<String> importEndTimeSet = dtoList.stream().map(d -> d.getEndTime().trim()).collect(Collectors.toSet());
        Set<String> unRegexEndTimeSet = new HashSet<>(importEndTimeSet);
        unRegexEndTimeSet.removeIf(m-> RegexConstant.YEAR_MONTH_DAY_REGEX.matcher(m).find());
        if(!Objects.isEmpty(unRegexEndTimeSet)){
            List<Integer> errorIndex = dtoList.stream().filter(d -> unRegexEndTimeSet.contains(d.getEndTime()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[抄表截止时间]格式错误.\n", errorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (isNull != null) {return isNull;}
        }
        List<Integer> readTimeErrorIndex = dtoList.stream().filter(d -> DailyUtil.intervalDays(d.getStartTime(), d.getEndTime()) < 0)
                .map(d -> d.getIndex()).collect(Collectors.toList());
        if(!Objects.isEmpty(readTimeErrorIndex)){
            errorMsg.append(String.format("第%s行,[抄表开始时间]必须小于[抄表截止时间].\n", readTimeErrorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, readTimeErrorIndex);
            if (isNull != null) {return isNull;}
        }

        List<Integer> totalTimeErrorIndex = dtoList.stream().filter(d -> DailyUtil.intervalDays(d.getEndTime(), d.getCreateTime()) < 0)
                .map(d -> d.getIndex()).collect(Collectors.toList());
        if(!Objects.isEmpty(totalTimeErrorIndex)){
            errorMsg.append(String.format("第%s行,[抄表截止时间]必须小于[抄表日期].\n", totalTimeErrorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, totalTimeErrorIndex);
            if (isNull != null) {return isNull;}
        }

        //因为批量保存，且需要获取上次读表数据，所以禁止出现重复的仪表号---------------------------------------------------
        List<String> meterNos = dtoList.stream().map(d -> d.getMeterNo().trim()).collect(Collectors.toList());
        List<String> repeatNos = meterNos.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());
        if (!Objects.isEmpty(repeatNos)) {
            List<Integer> errorIndex = dtoList.stream().filter(d -> repeatNos.contains(d.getMeterNo()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[仪表编号]重复(可能破坏数据有序性，造成读表逻辑错乱).\n", errorIndex));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (isNull != null) {return isNull;}
        }
        List<MeterManage> manages = jdbcSession.findArray(MeterManage.class)
                .in("meterNo", meterNos)
                .eq("deleted", false)
                .exe();
        if (Objects.isEmpty(manages)) {
            errorMsg.append("导入的[仪表编号]均不存在系统中.");
            return excelTool.R(importTotal,0,errorMsg.toString());
        }

        //判断无效仪表编号
        List<String> dbMeterNos = manages.stream().map(m -> m.getMeterNo()).collect(Collectors.toList());
        List<String> removeList = new ArrayList<>();
        removeList.addAll(meterNos);
        removeList.removeAll(dbMeterNos);
        if (!Objects.isEmpty(removeList)) {
            List<Integer> errorIndex = dtoList.stream().filter(d -> removeList.contains(d.getMeterNo()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[仪表编号]在系统中未找到.\n",errorIndex ));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (isNull != null) {return isNull;}
        }
        //判断仪表是否禁用
        List<String> stateCloses = manages.stream().filter(m -> !m.isStatus()).map(m -> m.getMeterNo()).collect(Collectors.toList());
        if(!Objects.isEmpty(stateCloses)){
            List<Integer> closeList = dtoList.stream().filter(d -> stateCloses.contains(d.getMeterNo()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,对应的[仪表编号]已被禁用，请移步仪表管理开启后再导入.\n",closeList ));
            ImportResult isNull = getImportResult(dtoList, importTotal, errorMsg, closeList);
            if (isNull != null) {return isNull;}
        }

        //一次性查询出所有仪表的上次读数
        Condition condition = Condition.create(false);
        condition.isNull("t2.meterNo");
        condition.in("t1.meterNo", meterNos);
        List<MeterReading> lastReading = chargeMeterDao.findLastReading(condition);

        //一次性查出所有用户信息
        Set<String> buildNameList = dtoList.stream().map(d -> d.getBuildName().trim()).collect(Collectors.toSet());
        Set<String> houseNumberList = dtoList.stream().map(d -> d.getHouseNumber().trim()).collect(Collectors.toSet());
        Set<String> communityNameList = dtoList.stream().map(d -> d.getCommunityName().trim()).collect(Collectors.toSet());

        JSONObject json = new JSONObject();
        json.put("communitySet",communityNameList);
        json.put("buildSet",buildNameList);
        json.put("houseNoSet",houseNumberList);
        List<ChargeHouseConfig> dbHouseConfigList = commonClient.getResidentListByMultipleQuery(json);

        //同一个月禁止二次导入
        Set<String> readYearMonthSet = dtoList.stream().map(d ->
                DateUtil.format(DateUtil.parse(d.getStartTime(), DateUtil.YEAR_MONTH_DAY), DateUtil.YEAR_MONTH))
                .collect(Collectors.toSet());

        List<MeterReading> dbReadingList = jdbcSession.findArray(MeterReading.class)
                .in("meterNo", meterNos)
                .in("readYearMonth", readYearMonthSet)
                .eq("deleted", false)
                .exe();

        //操作人信息-----------------------------------------------------------------------------------------------
        String departmentNo = null;
        String departmentName = null;
        List<String> departmentNos = null;
        String username = token.getUsername();
        List<String> departList = token.getDepartments();
        if (!Objects.isEmpty(departList)) {
            DeptDTO dept = deptService.getDept(departList.get(0));
            departmentNo = dept.getDepartmentNo();
            departmentName = dept.getDepartmentName();
            departmentNos = dept.getDepartmentNos();
        }
        //循环封装待ORM对象-----------------------------------------------------------------------------------------
        List<MeterReading> readingList = new ArrayList<>();
        for(Iterator<MeterReadingImportDTO> i = dtoList.iterator(); i.hasNext(); ) {
            MeterReadingImportDTO importDTO = i.next();
            //住户信息格式统一化
            String buildName = importDTO.getBuildName();
            if(!Objects.isEmpty(buildName) && !buildName.contains("栋")){
                importDTO.setBuildName(buildName+"栋");
            }
            String unitName = importDTO.getUnitName();
            if(!Objects.isEmpty(unitName) && !unitName.contains("单元")){
                importDTO.setUnitName(unitName+"单元");
            }

            List<Integer> index = new ArrayList<>();
            index.add(importDTO.getIndex());

            MeterReading meterReading = Pool.newInstance(MeterReading.class);
            importDTO.setCreateTime(importDTO.getCreateTime()+" 00:00:00");
            Beans.from((JSONObject) JSONObject.toJSON(importDTO)).to(meterReading).igornNull().copy();

            //excel没有的字段
            int num = DailyUtil.intervalDays(Java8TimeUtils.subStrDate(meterReading.getStartTime())
                    , Java8TimeUtils.subStrDate(meterReading.getEndTime()));
            meterReading.setUseDay(num);
            meterReading.setMeterNumber(CommonUtil.generateNumber("CB"));
            meterReading.setCreateName(username);
            meterReading.setDepartmentNo(departmentNo);
            meterReading.setDepartmentNos(departmentNos);
            meterReading.setDepartmentName(departmentName);

            //匹配仪表
            MeterManage meter = manages.stream().filter(m -> m.getMeterNo().equals(importDTO.getMeterNo())).findFirst().orElse(null);
            //可能仪表没有绑定
            if (StringUtil.isEmpty(meter.getMeterTypeNo())) {
                if (StringUtil.isEmpty(importDTO.getMeterClassifyName())) {
                    errorMsg.append(String.format("第%s行,[仪表编号]还没绑定住户，请填写[仪表分类]信息尝试.\n", index));
                    i.remove();
                    continue;
                }
                MeterClassify meterClass = jdbcSession.findOne(MeterClassify.class)
                        .eq("deleted", false)
                        .eq("typeName", importDTO.getMeterClassifyName())
                        .exe();
                meter.setMeterClassifyNo(meterClass.getId());
                meter.setMeterTypeNo(meterClass.getMeterTypeNo());
                meter.setMeterTypeName(meterClass.getMeterTypeName());
            }
            //仪表分类编号
            meterReading.setMeterClassifyNo(meter.getMeterClassifyNo());
            //仪表类型编号
            meterReading.setMeterTypeNo(meter.getMeterTypeNo());

            //住户信息------------------------------------------------------------------------------------------------
            List<ChargeHouseConfig> addressDataList = dbHouseConfigList.stream().filter(h ->
                    h.getCommunityName().equals(importDTO.getCommunityName())
                    && h.getBuildName().equals(importDTO.getBuildName())
                    && h.getMergeName().equals(importDTO.getHouseNumber())).collect(Collectors.toList());
            if(Objects.isEmpty(addressDataList)){
                errorMsg.append(String.format("第%s行,系统中没有找到该[房屋信息].\n", index));
                i.remove();
                continue;
            }
            ChargeHouseConfig houseConfig;
            if (!StringUtil.isEmpty(importDTO.getChargeName())) {
                houseConfig = addressDataList.stream().filter(a ->
                        a.getChargeName().equals(importDTO.getChargeName())).findFirst().orElse(null);
            }else {
                houseConfig = addressDataList.get(0);
            }
            if(null == houseConfig){
                errorMsg.append(String.format("第%s行,房屋信息中没有该[客户]，请检查姓名是否错误.\n", index));
                i.remove();
                continue;
            }
            //所属小区
            meterReading.setCommunityNo(houseConfig.getCommunityNo());
            //仪表地址
            meterReading.setMeterAddress(ConvertUtil.jointAddress(importDTO.getCommunityName()
                    ,importDTO.getBuildName(),importDTO.getUnitName(),importDTO.getHouseNumber()));
            //房屋编号
            meterReading.setHouseNo(houseConfig.getHouseNo());

            //获取之前的读表数据------------------------------------------------------------------------------------
            MeterReading meterLastReading = lastReading.stream().filter(l -> importDTO.getMeterNo().equals(l.getMeterNo())).findFirst().orElse(null);
            BigDecimal lastTimeNumber = BigDecimal.ZERO;
            BigDecimal timeUseNumber = new BigDecimal(importDTO.getTimeNumber());
            if (!Objects.isNull(meterLastReading)) {
                lastTimeNumber = meterLastReading.getTimeNumber();
                timeUseNumber = BigDecimalUtils.sub(timeUseNumber, lastTimeNumber, 2);
                //用户id
                meterReading.setUserNo(meterLastReading.getUserNo());
                //客户类型ID
                meterReading.setUserTypeNo(meterLastReading.getUserTypeNo());
            }
            if (BigDecimalUtils.isLessThan(timeUseNumber, BigDecimal.ZERO)) {
                errorMsg.append(String.format("第%s行,[本次读表]不能小于[上次读表],请核实.\n", index));
                i.remove();
                continue;
            }
            //上次读数
            meterReading.setLastTimeNumber(lastTimeNumber);
            //本月用量
            meterReading.setTimeUseNumber(timeUseNumber);
            //抄表年月 -
            Date date = DateUtil.parse(importDTO.getStartTime(), DateUtil.YEAR_MONTH_DAY);
            String yearMonth =DateUtil.format(date,DateUtil.YEAR_MONTH);
            meterReading.setReadYearMonth(yearMonth);
            //抄表本月 -
            String year =DateUtil.format(date,DateUtil.YEAR);
            meterReading.setReadMonth(year);

            long count = dbReadingList.stream().filter(r ->
                    yearMonth.equals(r.getReadYearMonth()) && importDTO.getMeterNo().equals(r.getMeterNo())).count();

            if(count>0){
                errorMsg.append(String.format("第%s行,本月该[仪表]已经有抄表数据(若需要修改请移步具体页面修改).\n", index));
                i.remove();
                continue;
            }

            readingList.add(meterReading);
        }
        int successCount = jdbcSession.insert(readingList).length;
        return excelTool.R(importTotal,successCount,errorMsg.toString());
    }


    private ImportResult getImportResult(List<MeterReadingImportDTO> dtoList, int importTotal, StringBuilder errorMsg, List<Integer> errorIndex) {
        dtoList.removeIf(d->errorIndex.contains(d.getIndex()));
        if(Objects.isEmpty(dtoList)){
            return excelTool.R(importTotal,0, errorMsg.toString());
        }
        return null;
    }


    @Override
    public Object save(MeterReading meterReading, Token token) throws Exception {
        MeterManage manage = jdbcSession.findOne(MeterManage.class)
                .eq("deleted", false)
                .eq("meterNo", meterReading.getMeterNo())
                .exe();
        if(null == manage || !manage.isStatus()){
            return Result.error(0,"此仪表已被关闭，需要开启后才能抄表");
        }

        meterReading.setCreateName(token.getUsername());

        List<String> departList = token.getDepartments();
        DeptDTO deptDTO = null;
        if (null != departList && departList.size() > 0) {
            logger.error("用户{}数据异常，部门为空！", token.getUsername());
            deptDTO = deptService.getDept(departList.get(0));
            meterReading.setDepartmentNo(deptDTO.getDepartmentNo());
            meterReading.setDepartmentNos(deptDTO.getDepartmentNos());
            meterReading.setDepartmentName(deptDTO.getDepartmentName());
        }
        meterReading.setMeterNumber(CommonUtil.generateNumber("CB"));

        if(Objects.isNull(meterReading.getMeterNo())){
            return Result.error(1212,"仪表编号为空，请先绑定仪表！");
        }

        if(Objects.isNull(meterReading.getEndTime()) || Objects.isNull(meterReading.getStartTime())){
            return Result.error(1213,"计数区间时间必须填写！");
        }

        //1、计算天数
        int num = DailyUtil.intervalDays(Java8TimeUtils.subStrDate(meterReading.getStartTime())
                , Java8TimeUtils.subStrDate(meterReading.getEndTime())) + 1;
        meterReading.setUseDay(num);

        String endDate = meterReading.getEndTime().substring(0, 7);
        if (Objects.isBlank(meterReading.getReadYearMonth())) {
            meterReading.setReadYearMonth(endDate);
        }
        jdbcSession.insert(meterReading);

        // 查询此月所有的抄表数据
        BigDecimal timeUseNumber = BigDecimal.ZERO;
        List<MeterReading> meterReadingList = jdbcSession.findArray(MeterReading.class)
                .eq("deleted", false)
                .eq("houseNo", meterReading.getHouseNo())
                .eq("readYearMonth", meterReading.getReadYearMonth())
                .eq("meterTypeNo", meterReading.getMeterTypeNo())
                .exe();
        for (MeterReading each : meterReadingList) {
            timeUseNumber = BigDecimalUtils.add(timeUseNumber, each.getTimeUseNumber(), 2);
        }

        //2、添加统计数据
        String startDate = meterReading.getStartTime().substring(0, 7);

        Set<String> monthSet = DailyUtil.getIntervalMonth(startDate, endDate);
        for (String each : monthSet) {
            List<MeterReadStatist> readList = jdbcSession.findArray(MeterReadStatist.class)
                    .eq("deleted", false)
                    .eq("houseNo",meterReading.getHouseNo())
                    .eq("readYearMonth",each)
                    .eq("meterTypeNo",meterReading.getMeterTypeNo())
                    .exe();
            if (readList.size() == 0) {
                //添加数据
                MeterReadStatist config = Pool.newInstance(MeterReadStatist.class);
                config.setCommunityNo(manage.getCommunityNo());
                config.setCommunityName(manage.getCommunityName());
                config.setHouseNo(manage.getHouseNo());
                config.setMeterAddress(manage.getMeterAddress());
                config.setMeterClassifyNo(manage.getMeterClassifyNo());
                config.setMeterNo(manage.getMeterNo());
                config.setMeterTypeName(manage.getMeterTypeName());
                config.setMeterClassifyName(manage.getMeterClassifyName());
                config.setReadYearMonth(each);
                config.setMeterTypeNo(meterReading.getMeterTypeNo());
                config.setMeterNumber(meterReading.getMeterNumber());
                config.setReadStatus("2");
                config.setFeeStatus("2");
                if (deptDTO != null) {
                    config.setDepartmentNo(deptDTO.getDepartmentNo());
                    config.setDepartmentNos(deptDTO.getDepartmentNos());
                    config.setDepartmentName(deptDTO.getDepartmentName());
                }

                boolean isEnd = each.equals(endDate);
                BigDecimal zeroDecimal = new BigDecimal(0);
                config.setTimeNumber(isEnd ? meterReading.getTimeNumber() : zeroDecimal);
                config.setTimeUseNumber(isEnd ? meterReading.getTimeUseNumber() : zeroDecimal);

                int maxOfMonth = DailyUtil.getMaxOfMonth(DailyUtil.parse(each, "yyyy-MM"));
                config.setStartTime(each + "-01");
                config.setEndTime(each + "-" + maxOfMonth);
                config.setCreateName(meterReading.getCreateName());
                jdbcSession.insert(config);
            } else {
                for (int i = 0; i < readList.size(); i++) {
                    MeterReadStatist readStatist = readList.get(i);
                    readStatist.setReadStatus("2");
                    readStatist.setFeeStatus("2");
                    readStatist.setMeterNo(meterReading.getMeterNo());
                    readStatist.setMeterClassifyName(meterReading.getMeterClassifyName());
                    readStatist.setMeterClassifyNo(meterReading.getMeterClassifyNo());
                    readStatist.setMeterTypeName(meterReading.getMeterTypeName());
                    readStatist.setMeterAddress(meterReading.getMeterAddress());
                    readStatist.setTimeNumber(meterReading.getTimeNumber());
                    readStatist.setTimeUseNumber(timeUseNumber);
                    readStatist.setCreateName(meterReading.getCreateName());
                    readStatist.setMeterNumber(meterReading.getMeterNumber());
                    jdbcSession.updateById(readStatist);
                }
            }
        }

        commonService.insetLogger(meterReading.getMeterNo(),
                ChargeLogEnum.LOG_CHARGE_METER_READ.getDesc(),
                "添加抄表数据",
                ChargeStatusEnum.CS_SUCCESS.getDesc(),
                ChargeStatusEnum.CS_SUCCESS.getDesc(), "操作成功", token.getUsername());

        return Result.success();
    }




    @Override
    public Object save(MeterReading meterReading) {
        return null;
    }


    @Override
    public Object update(MeterReading meterReading) {

        int num = DailyUtil.intervalDays(Java8TimeUtils.subStrDate(meterReading.getStartTime())
                , Java8TimeUtils.subStrDate(meterReading.getEndTime())) + 1;
        meterReading.setUseDay(num);

        commonService.insetLogger(meterReading.getMeterNo(),
                ChargeLogEnum.LOG_CHARGE_METER_READ.getDesc(),
                "修改抄表数据",
                ChargeStatusEnum.CS_SUCCESS.getDesc(),
                ChargeStatusEnum.CS_SUCCESS.getDesc(), "操作成功", meterReading.getUpdateName());

        int result = jdbcSession.updateById(meterReading);

        // 查询此月所有的抄表数据
        BigDecimal timeUseNumber = BigDecimal.ZERO;
        List<MeterReading> meterReadingList = jdbcSession.findArray(MeterReading.class)
                .eq("deleted", false)
                .eq("houseNo", meterReading.getHouseNo())
                .eq("readYearMonth", meterReading.getReadYearMonth())
                .eq("meterTypeNo", meterReading.getMeterTypeNo())
                .exe();
        for (MeterReading each : meterReadingList) {
            timeUseNumber = BigDecimalUtils.add(timeUseNumber, each.getTimeUseNumber(), 2);
        }

        // 若读数不一致则更新统计
        List<MeterReadStatist> readList = jdbcSession.findArray(MeterReadStatist.class)
                .eq("deleted", false)
                .eq("houseNo",meterReading.getHouseNo())
                .eq("readYearMonth",meterReading.getReadYearMonth())
                .eq("meterTypeNo",meterReading.getMeterTypeNo())
                .exe();
        for (MeterReadStatist each : readList) {
            each.setTimeNumber(meterReading.getTimeNumber());
            each.setTimeUseNumber(timeUseNumber);
            jdbcSession.updateById(each);
        }
        return result;
    }


    @Override
    public Object deleteById(String id) {
        MeterReading result = Pool.get(MeterReading.class, id);
        if (result != null) {
            result.setDeleted(true);
            jdbcSession.updateById(result);
        }
        return 1;
    }


    /**
     * 需求变更，方法作废
     * @param jsonObject
     * @param token
     * @return
     * @throws Exception
     */
    public Page<MeterReadStatistDTO> findStatistHouse(JSONObject jsonObject, Token token) throws Exception {

        PageCondition query = Condition.createPage(false);

        String communityNo = jsonObject.getString("communityNo");
        if (!StringUtil.isEmpty(communityNo)) {
            query.eq("communityNo", communityNo);
        }
        String meterMonth = jsonObject.getString("readYearMonth");
        if (StringUtil.isEmpty(meterMonth)) {
            meterMonth = DailyUtil.get_yyyy_MM(); //为空则获取本月的年月
            jsonObject.put("readYearMonth", meterMonth);
        }
        String readStatus = jsonObject.getString("readStatus");
        if(!StringUtil.isEmpty(readStatus)){
            query.eq("readStatus",readStatus);
        }

        //先同步数据，再进行统计
        synHouseData(jsonObject,token);

        query.eq("meterTypeNo", jsonObject.getString("meterTypeNo"));
        query.eq("readYearMonth", meterMonth);
        query.eq("deleted", false);
        query.groupBy("communityNo");
        query.groupBy("readYearMonth");
        query.page(jsonObject);
        Page<HashMap> statist = chargeMeterDao.findStatist(query);
        return convert(statist);
    }

    @Override
    public Page<MeterReadStatistDTO> findStatist(JSONObject jsonObject, Token token) throws Exception {

        PageCondition query = Condition.createPage(false);

        String communityNo = jsonObject.getString("communityNo");
        if (!StringUtil.isEmpty(communityNo)) {
            query.eq("communityNo", communityNo);
        }
        String meterMonth = jsonObject.getString("readYearMonth");
        if (StringUtil.isEmpty(meterMonth)) {
            meterMonth = DailyUtil.get_yyyy_MM(); //为空则获取本月的年月
            jsonObject.put("readYearMonth", meterMonth);
        }
        String readStatus = jsonObject.getString("readStatus");
        if(!StringUtil.isEmpty(readStatus)){
            query.eq("readStatus",readStatus);
        }

        //先同步数据，再进行统计
        synHouseData(jsonObject,token);

        query.eq("meterTypeNo", jsonObject.getString("meterTypeNo"));
        query.eq("readYearMonth", meterMonth);
        query.eq("deleted", false);
        query.groupBy("communityNo");
        query.groupBy("readYearMonth");
        query.page(jsonObject);
        Page<HashMap> statist = chargeMeterDao.findStatist(query);
        return convert(statist);
    }

    private Page<MeterReadStatistDTO> convert(Page<HashMap> statist) {
        Page<MeterReadStatistDTO> result = new Page<>();
        result.setPageSize(statist.getPageSize());
        result.setPageNo(statist.getPageNo());
        result.setPageCount(statist.getPageCount());
        result.setCount(statist.getCount());
        result.setOffSet(statist.getOffSet());
        List<HashMap> list = statist.getList();
        if (Objects.nonEmpty(list)) {
            List<MeterReadStatistDTO> dataList = new ArrayList<>();
            for (HashMap each : list) {
                MeterReadStatistDTO item = new MeterReadStatistDTO();
                String meterNumber = each.get("meterNumber").toString();
                item.setMeterNumber(Integer.parseInt(meterNumber));
                item.setMeterReading(Integer.parseInt(each.get("meterReading").toString()));
                item.setMeterReadNot(Integer.parseInt(each.get("meterReadNot").toString()));
                item.setMeterTypeName((String) each.get("meterTypeName"));
                item.setMeterTypeNo((String) each.get("meterTypeNo"));
                item.setMonthTotal((BigDecimal) each.get("monthTotal"));
                item.setCommunityName((String) each.get("communityName"));
                item.setCommunityNo((String) each.get("communityNo"));
                item.setReadYearMonth((String) each.get("readYearMonth"));
                dataList.add(item);
            }
            result.setList(dataList);
        }
        return result;
    }

    /**
     * 同步房屋数据
     * @param jsonObject
     * @param token
     * @return
     * @throws Exception
     */
    private synchronized void synHouseData(JSONObject jsonObject,Token token) throws Exception {
        List<String> departList = token.getDepartments();
        if(Objects.isEmpty(departList)){
            return;
        }
        List<MeterManage> listManage = jdbcSession.findArray(MeterManage.class).eq("deleted", false)
                .eq("meterTypeNo",jsonObject.getString("meterTypeNo"))
                .exe();

        for (MeterManage manage : listManage) {
            //添加数据
            DeptDTO deptDTO = deptService.getDept(departList.get(0));
            insetData(manage,deptDTO,jsonObject, "1");
        }
    }

    /**
     * 添加房屋绑定设置
     */
    private void insetData(MeterManage manage,DeptDTO deptDTO,JSONObject jsonObject, String readStatus){
        List<MeterReadStatist> statistList = jdbcSession.findArray(MeterReadStatist.class).eq("houseNo", manage.getHouseNo())
                .eq("meterTypeNo", jsonObject.getString("meterTypeNo")).eq("readYearMonth", jsonObject.getString("readYearMonth"))
                .eq("deleted", 0).exe();
        if (statistList.size() > 0) {
            logger.info("已统计");
            return;
        }

        MeterReadStatist config = Pool.newInstance(MeterReadStatist.class);
        config.setCommunityNo(manage.getCommunityNo());
        config.setCommunityName(manage.getCommunityName());
        config.setHouseNo(manage.getHouseNo());
        config.setMeterAddress(manage.getMeterAddress());
        config.setMeterClassifyNo(manage.getMeterClassifyNo());
        config.setMeterNo(manage.getMeterNo());
        config.setMeterTypeName(manage.getMeterTypeName());
        config.setMeterClassifyName(manage.getMeterClassifyName());
        config.setReadYearMonth(jsonObject.getString("readYearMonth"));
        config.setMeterTypeNo(jsonObject.getString("meterTypeNo"));
        config.setReadStatus(readStatus);
        config.setFeeStatus("1");
        if (deptDTO != null) {
            config.setDepartmentNo(deptDTO.getDepartmentNo());
            config.setDepartmentNos(deptDTO.getDepartmentNos());
            config.setDepartmentName(deptDTO.getDepartmentName());
        }

        jdbcSession.insert(config);
    }

    @Override
    public Page<MeterReadStatist> findReadStatist(JSONObject jsonObject) {

        FindPage<MeterReadStatist> find = jdbcSession.findPage(MeterReadStatist.class);
        find.eq("deleted", false);
        find.like(jsonObject, "meterNo");
        find.eq(jsonObject, "communityNo");
        find.eq(jsonObject, "meterTypeNo");
        find.eq(jsonObject, "readYearMonth");
        find.eq(jsonObject, "readStatus");
        //添加选中导出条件
        JSONArray exportIdList = jsonObject.getJSONArray("exportIdList");
        if(!Objects.isEmpty(exportIdList)){
            find.in("id",exportIdList);
        }
        find.order("createTime", "desc");

        return find.page(jsonObject).exe();
    }

    @Override
    public void findReadStatistExport(HttpServletRequest req, HttpServletResponse resp, JSONObject jsonObject) {
        jsonObject.put("pageNo", 1);
        jsonObject.put("pageSize", Short.MAX_VALUE);
        List<MeterReadStatist> list = findReadStatist(jsonObject).getList();
        Assert.notEmpty(list,"没有找到相关的抄表数据.");
        List<MeterReadStatistExcelVO> dtoList = ListUtils.copyBeanList(list, MeterReadStatistExcelVO::new);
        String meterTypeName = list.get(0).getMeterTypeName();
        meterTypeName = StringUtil.isEmpty(meterTypeName) ? "" : meterTypeName;
        excelTool.excelDownload(req, resp, dtoList, meterTypeName + "类型抄表导出");
    }


    @Override
    public void statistExport(HttpServletRequest req, HttpServletResponse resp, JSONObject jsonObject, Token token) throws Exception {
        jsonObject.put("pageNo", 1);
        jsonObject.put("pageSize", Short.MAX_VALUE);
        List<MeterReadStatistDTO> statist = findStatist(jsonObject, token).getList();
        Assert.notEmpty(statist,"没有找到相关的抄表数据.");
        String meterTypeName = statist.get(0).getMeterTypeName();
        meterTypeName = StringUtil.isEmpty(meterTypeName) ? "" : meterTypeName;
        excelTool.excelDownload(req, resp, statist, meterTypeName + "抄表统计导出");
    }


    @Override
    public MeterReading findMeterObj(JSONObject jsonObject) {
        return jdbcSession.findOne(MeterReading.class)
                .eq("deleted", false)
                .eq(jsonObject, "meterAddress")
                .exe();
    }


    @Override
    public Object batchDelete(JSONObject jsonObject) {
        List<MeterReading> reds = jdbcSession.findArray(MeterReading.class)
                .in("id", jsonObject.getJSONArray("ids"))
                .exe();
        int num = 0;
        for (MeterReading reading : reds) {
            reading.setDeleted(true);
            num = jdbcSession.updateById(reading);
        }
        return num;
    }


    @Override
    public Object getObj(JSONObject jsonObject) {

        //一个月可以抄表多次
        List<MeterReading> meterReadings = jdbcSession.findArray(MeterReading.class)
                .eq("deleted", false)
                .eq(jsonObject, "meterAddress")
                .eq(jsonObject, "houseNo")
                .eq(jsonObject, "meterNumber")
                .eq(jsonObject,"meterTypeNo")
                .exe();
        if (meterReadings.size() > 0) {
            return meterReadings.get(0);
        }

        return meterReadings;
    }


}
